package com.gan.simple_init.quartz.service.Impl;

import java.util.Date;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gan.simple_init.common.base.PageRequest;
import com.gan.simple_init.common.base.ResponseErrorEnum;
import com.gan.simple_init.common.base.RestResultGenerator;
import com.gan.simple_init.common.constant.CommonConstant;
import com.gan.simple_init.common.exception.BusinessException;
import com.gan.simple_init.model.user.entity.LoginUser;
import com.gan.simple_init.quartz.mapper.SysJobMapper;
import com.gan.simple_init.quartz.model.SysJob;
import com.gan.simple_init.quartz.model.dto.SysJobDTO;
import com.gan.simple_init.quartz.service.SysJobService;
import com.gan.simple_init.quartz.util.JobStatusEnum;
import com.gan.simple_init.quartz.util.QuartzManager;
import com.gan.simple_init.util.UserCacheUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author gbw
 * @description 针对表【sys_job(定时任务表)】的数据库操作Service实现
 * @createDate 2023-08-20 15:40:38
 */
@Service
public class SysJobServiceImpl extends ServiceImpl<SysJobMapper, SysJob>
        implements SysJobService {

    @Resource
    private SysJobMapper sysJobMapper;

    @Resource
    private QuartzManager quartzManager;

    @Override
    public SysJob get(Long id) {
        return sysJobMapper.selectById(id);
    }

    @Override
    public boolean save(SysJob sysJob) throws BusinessException {
        try {
            //获取当前用户
            LoginUser user = UserCacheUtil.getUserCache();
            String userName = user.getUserName();
            sysJob.setCreateBy(userName);
            sysJob.setUpdateBy(userName);
            // 默认任务有效
            sysJob.setJobStatus(JobStatusEnum.RUNNING.getInfo());

            if (CommonConstant.IsValid.NOT_VALID.equals(sysJob.getIsValid())) {
                sysJob.setJobStatus(JobStatusEnum.UN_VALID.getInfo());
                return sysJobMapper.insert(sysJob) > 0;
            }
            // 不先插入数据库的话就没有 jobId
            boolean flag = sysJobMapper.insert(sysJob) > 0;
            quartzManager.addJob(sysJob);
            return flag;
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("插入数据出错");
        }
    }


    @Override
    public Integer remove(Long id) throws BusinessException {
        SysJob job = get(id);
        if (CommonConstant.IsValid.VALID.equals(job.getIsValid())) {
            throw new BusinessException("请将任务状态设为失效");
        }
        try {
            quartzManager.deleteJob(job);
            return sysJobMapper.deleteById(id);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("删除数据出错");
        }

    }


    @Override
    public void initSchedule() throws BusinessException {
        try {
            // 获取所有有效的任务信息数据
            QueryWrapper<SysJob> qw = new QueryWrapper<>();
            qw.eq("isValid", CommonConstant.IsValid.VALID);
            List<SysJob> jobList = list();
            for (SysJob task : jobList) {
                quartzManager.addJob(task);
                task.setJobStatus(JobStatusEnum.RUNNING.getInfo());
                // 避免前面的成功了后面的报错了，需要每一条成功之后就要更新以下数据库
                updateById(task);
            }
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("初始化出错");
        }
    }

    @Override
    public void changeStatus(Long jobId, String isValid) throws BusinessException {
        try {
            SysJob job = get(jobId);
            // 获取当前用户
            LoginUser user = UserCacheUtil.getUserCache();
            String userName = user.getUserName();
            job.setUpdateBy(userName);
            job.setIsValid(isValid);

            if (CommonConstant.IsValid.VALID.equals(isValid)) {
                quartzManager.addJob(job);
                job.setJobStatus(JobStatusEnum.RUNNING.getInfo());
            } else {
                quartzManager.deleteJob(job);
                job.setJobStatus(JobStatusEnum.UN_VALID.getInfo());
            }
            sysJobMapper.updateById(job);
        } catch (Exception e) {
            throw new BusinessException("更新任务状态出错");
        }
    }

    @Override
    public void updateCron(Long jobId, String cron) throws BusinessException {
        // 更新表达式后需要重新更新任务状态
        SysJob job = get(jobId);
        try {
            //获取当前用户
            LoginUser user = UserCacheUtil.getUserCache();
            String userName = user.getUserName();
            job.setUpdateBy(userName);
            job.setCronExpression(cron);

            quartzManager.updateJobCron(job);
            sysJobMapper.updateById(job);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("更新任务Cron表达式出错");
        }
    }


    @Override
    public void run(SysJob task) throws BusinessException {
        if (!JobStatusEnum.RUNNING.getInfo().equals(task.getJobStatus())) {
            throw new BusinessException("执行前请先开启任务！");
        }
        try {
            quartzManager.runJobNow(task);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("运行任务出错");
        }
    }

    @Override
    public boolean validJob(SysJob sysJob) {

        String jobName = sysJob.getJobName();
        String cronExpression = sysJob.getCronExpression();
        String beanClass = sysJob.getBeanClass();
        String jobGroup = sysJob.getJobGroup();
        String isValid = sysJob.getIsValid();

        if (StringUtils.isAnyBlank(jobName, isValid, jobGroup, beanClass, cronExpression)) {
            throw new BusinessException(ResponseErrorEnum.ILLEGAL_PARAMS);
        }
        if (!CommonConstant.IsValid.VALID.equals(isValid) && !CommonConstant.IsValid.NOT_VALID.equals(isValid)) {
            throw new BusinessException("有效性非法!");
        }
        // 查询有没有这个方法
        try {
            Class.forName(beanClass);
        } catch (ClassNotFoundException e) {
            throw new BusinessException("查询不到该任务!");
        }
        return true;
    }


    @Override
    public Page<SysJobDTO> listSysJob(PageRequest pageRequest) throws BusinessException {
        try {
            Page<SysJob> page = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
            // 查询有效的任务，根据时间排序
            IPage<SysJob> pageList = sysJobMapper.selectPage(page, new QueryWrapper<SysJob>()
                    .eq("isValid", CommonConstant.IsValid.VALID));

            List<SysJob> records = pageList.getRecords();
            long total = records.size();
            // 转换为DTO
            List<SysJobDTO> list = records
                    .stream().map((r) -> {
                        // 属性复制
                        SysJobDTO d = new SysJobDTO();
                        BeanUtil.copyProperties(r, d);
                        return d;
                    }).collect(Collectors.toList());
            Page<SysJobDTO> sysJobDTOPage = new Page<>();
            sysJobDTOPage.setRecords(list);
            sysJobDTOPage.setTotal(total);
            return sysJobDTOPage;
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("查询列表出错");
        }
    }


    @Override
    public boolean removeBatch(Long[] ids) throws BusinessException {
        try {
            for (Long id : ids) {
                try {
                    SysJob task = get(id);
                    quartzManager.deleteJob(task);
                } catch (SchedulerException e) {
                    e.printStackTrace();
                    return false;
                }
            }
            List<Long> idList = Arrays.asList(ids);
            QueryWrapper<SysJob> qw = new QueryWrapper<>();
            qw.in("id", idList);
            return this.getBaseMapper().deleteBatchIds(idList) > 0;
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
            throw new BusinessException("删除数据出错");
        }
    }

    @Override
    public boolean resumeBatch(Long[] ids) throws BusinessException {
        List<SysJob> jobList = list(new QueryWrapper<SysJob>().in(ids != null, "id", Arrays.asList(ids)));

        jobList.forEach((job) -> {
            if (JobStatusEnum.UN_VALID.getInfo().equals(job.getJobStatus())) {
                throw new BusinessException("请先启动任务!");
            }
            if (JobStatusEnum.RUNNING.getInfo().equals(job.getJobStatus())) {
                throw new BusinessException("任务正在运行!");
            }
            try {
                quartzManager.resumeJob(job);
            } catch (SchedulerException e) {
                throw new RuntimeException(e);
            }
            job.setJobStatus(JobStatusEnum.RUNNING.getInfo());
        });
        updateBatchById(jobList);
        return true;
    }

    @Override
    public boolean pauseBatch(Long[] ids) throws BusinessException {
        List<SysJob> jobList = list(new QueryWrapper<SysJob>().in(ids != null, "id", Arrays.asList(ids)));

        jobList.forEach((job) -> {
            if (JobStatusEnum.UN_VALID.getInfo().equals(job.getJobStatus())) {
                throw new BusinessException("请先启动任务!");
            }
            if (JobStatusEnum.PAUSE.getInfo().equals(job.getJobStatus())) {
                throw new BusinessException("任务已被暂停!");
            }
            try {
                quartzManager.pauseJob(job);
            } catch (SchedulerException e) {
                throw new RuntimeException(e);
            }
            job.setJobStatus(JobStatusEnum.PAUSE.getInfo());
        });
        updateBatchById(jobList);
        return true;
    }


}




